﻿using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;

namespace Language.Intellisense.Signature
{
    internal sealed class CommandHandler : IOleCommandTarget
    {
        #region Private Data

        private IOleCommandTarget _nextCommandHandler;
        private ITextView _textView;
        private ISignatureHelpBroker _broker;
        private ISignatureHelpSession _session;

        #endregion Private Data

        #region C-Tor

        public CommandHandler( IVsTextView textViewAdapter, ITextView textView, ISignatureHelpBroker broker )
        {
            _textView = textView;
            _broker = broker;

            //add the command to the command chain
            textViewAdapter.AddCommandFilter( this, out _nextCommandHandler );
        }

        #endregion C-Tor

        #region IOleCommandTarget

        int IOleCommandTarget.Exec( ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut )
        {
            int result = _nextCommandHandler.Exec( ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut );

            char typedChar = char.MinValue;

            if( _session?.IsDismissed == true )
            {
                _session = null;
            }

            if ( pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR )
            {
                typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant( pvaIn );

                if ( ( typedChar.Equals( '(' ) || typedChar.Equals( ',' ) ) && _session == null )
                {
                    _session = _broker.TriggerSignatureHelp( _textView );
                }
            }

            return result;
        }

        int IOleCommandTarget.QueryStatus( ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText )
        {
            if ( pguidCmdGroup == VSConstants.VSStd2K )
            {
                switch ( (VSConstants.VSStd2KCmdID)prgCmds[ 0 ].cmdID )
                {
                    case VSConstants.VSStd2KCmdID.PARAMINFO:
                        prgCmds[ 0 ].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED;
                        return VSConstants.S_OK;
                }
            }

            return _nextCommandHandler.QueryStatus( ref pguidCmdGroup, cCmds, prgCmds, pCmdText );
        }

        #endregion IOleCommandTarget
    }
}
